/*
 *  Filename:lsv_log_gc_logctrl.c
 *  Description:
 *
 *  Created on: 2017年3月27日
 *  Author: Asdf(825674301)
 */
#include "lsv_conf.h"
#include "lsv_help.h"
#include "lsv_log.h"
#include "lsv_volume.h"
#include "lsv_gc.h"

//cmp logctrl and chunkid
int __lsv_gc_logctrl_cmp(const void *_logctrl, const void *_chunkid) {
        const lsv_gc_logctrl_t *logctrl = _logctrl;
        const lsv_u32_t *chunkid = _chunkid;

        if (logctrl->chunk_id > *chunkid)
                return 1;
        else if (logctrl->chunk_id < *chunkid)
                return -1;
        else
                return 0;
}

static inline int __lsv_log_gc_hhlog_read(lsv_volume_proto_t *lsv_info, lsv_u32_t chunk_id, lsv_u32_t size,
                lsv_s8_t *buf) {
#if LSV_GC_LOGCTRL_READ_TYPE == 1
        //read from storage
        return lsv_volume_chunk_read_data(lsv_info, LSV_THIS_VOL_INO, chunk_id, 0, size, buf);
#elif LSV_GC_LOGCTRL_READ_TYPE ==2
        //read from cache
        return lsv_rcache_lookup(lsv_info, chunk_id, 0, size, buf);
#else
        return -EPERM;
#endif
}

void __lsv_gc_logctrl_free(void *arg) {
        lsv_gc_logctrl_t *logctrl = arg;
        if (logctrl) {
                CHUNK_HISTORY("gc free", logctrl);

#if LSV_GC_LOGCTRL_HLOG_TYPE==2
                if (logctrl->hlog) {
                        free(logctrl->hlog);
                        logctrl->hlog = NULL;
                }
#endif
                free(logctrl);
        }
}

void lsv_gc_logctrl_free(lsv_volume_proto_t *lsv_info, lsv_gc_logctrl_t *logctrl) {
        if (logctrl) {
#ifdef IS_STORAGE_BITMAP
                lsv_gc_bitmap_use(lsv_info, logctrl->chunk_id, 0);
#endif
                __lsv_gc_logctrl_free(logctrl);

                DINFO("chunk_id %u for_gc %u ts %ju page %u crc %u\n",
                      logctrl->chunk_id,
                      logctrl->for_gc,
                      logctrl->head.timestamp,
                      logctrl->head.page_count,
                      logctrl->head.crc);
        }
}

int lsv_gc_logctrl_create(lsv_volume_proto_t *lsv_info, int for_gc, lsv_log_proto_t log_proto,
                          lsv_gc_logctrl_t **logctrl) {
        int ret = 0;
        lsv_log_info_t *log_info = NULL;
        lsv_gc_context_t *gc_context = NULL;
        lsv_gc_logctrl_t *this_logctrl = NULL;

        log_info = lsv_info->log_info;
        gc_context = log_info->gc_context;

        // TODO recovery: log_proto.log == NULL
        // YASSERT(log_proto.log != NULL);

        ret = ymalloc((void **)&this_logctrl, sizeof(lsv_gc_logctrl_t));
        if (unlikely(ret)) {
                ret = -ENOMEM;
                DERROR("malloc logctrl failed, ret %d\n", ret);
                goto ERR;
        }

        INIT_LIST_HEAD(&this_logctrl->hook);
        this_logctrl->chunk_id = log_proto.chunk_id;

#if LSV_GC_LOGCTRL_HLOG_TYPE==1
        this_logctrl->head = *(log_proto.head);
        memcpy(this_logctrl->hlog, log_proto.hlog, LSV_LOG_HLOG_AREA);
#else
        if (NULL == log_proto.log) {
                this_logctrl->head.page_count = LSV_LOG_PAGE_NUM + 1;
        } else {
                this_logctrl->head = *(log_proto.head);
        }

        this_logctrl->hlog = NULL;
#endif

        this_logctrl->for_gc = for_gc;
        this_logctrl->gc_count = 0;
        this_logctrl->gc_value = 0;
        lp_bitmap_init(&this_logctrl->lp_bm);

#ifdef IS_STORAGE_BITMAP
        if (gc_context->bitmap_is_open) {
                ret = lsv_gc_bitmap_use(lsv_info, this_logctrl->chunk_id, 1);
                if (ret < 0) {
                        DERROR("use storage_bitmap failed,errno:%d\n", ret);
                        goto ERR;
                }
        }
#endif

        DINFO("chunk_id %u for_gc %u ts %ju page %u crc %u\n",
              this_logctrl->chunk_id,
              this_logctrl->for_gc,
              this_logctrl->head.timestamp,
              this_logctrl->head.page_count,
              this_logctrl->head.crc);

        *logctrl = this_logctrl;

        return 0;
ERR:
        __lsv_gc_logctrl_free(this_logctrl);
        return ret;
}
